/**
 * 
 */
package smallChanges.Tokenization;

import java.util.HashSet;
import java.util.Set;

import net.sourceforge.pmd.ast.JavaParserConstants;
import net.sourceforge.pmd.ast.Token;
import smallChanges.util.HashCodeUtil;

/**
 * @author jspacco
 *
 */
public class SCToken extends CodeRange2D
{
    private UniqueToken uniqueToken=new UniqueToken();
    private Long tokenID;
    private Long fileID;
    private Long transID;
    
    public SCToken() {}
    
    public SCToken(Long tokenID, int beginLine, int beginColumn, int endLine, int endColumn, String image)
    {
    	super(beginLine,beginColumn,endLine,endColumn);
    	this.tokenID=tokenID;
    	this.setImage(image);
    }
    
    public SCToken(int beginLine, int beginColumn, int endLine, int endColumn)
    {
    	super(beginLine, beginColumn, endLine, endColumn);
    }
    
    public SCToken(Token token) {
        this(token.beginLine, token.beginColumn, token.endLine, token.endColumn);
        this.uniqueToken.setImage(token.image);
        this.uniqueToken.setKind(convertPMDTokenKindToDBEnum(token.kind));
    }
    
    public SCToken(Token token, Long fileID, Long transID) {
        this(token);
        this.fileID=fileID;
        this.transID=transID;
    }
    
    
    
//    public static SCToken lookupByFileIDAndCoords(Long fileID, int beginLine,
//            int beginColumn, int endLine, int endColumn, Session session)
//    {
//        SCToken result=(SCToken)session.createQuery(" select t from SCToken t " +
//        		" where FileID = :fileID " +
//        		COORDS_QUERY
//        		).setLong("fileID", fileID).
//        		setInteger("beginLine", beginLine).
//        		setInteger("beginColumn", beginColumn).
//        		setInteger("endLine", endLine).
//        		setInteger("endColumn", endColumn).uniqueResult();
//        result.fillInUniqueToken(session);
//        return result;
//    }
    
    public boolean equals(Object o) {
        if (!(o instanceof SCToken))
            return false;
        if (o==null)
            return false;
        SCToken other=(SCToken)o;
        return this.beginLine==other.beginLine &&
            this.endLine==other.endLine &&
            this.beginColumn==other.beginColumn &&
            this.endColumn==other.endColumn &&
            this.uniqueToken != null &&
            this.uniqueToken.equals(other.uniqueToken);
    }
    
    public String toString() {
        return "("+beginLine+", "+beginColumn+") " +getImage()+" ("+endLine+ ", "+endColumn+")";
    }
    
    public int hashCode() {
        // TODO include all the fields used in the equals() method 
        int result=super.hashCode();
        result = HashCodeUtil.hash(result, getImage());
        result = HashCodeUtil.hash(result, getKind());
        return result;
    }
    
	public Long getTokenID()
    {
        return tokenID;
    }
    public void setTokenID(Long tokenPK)
    {
        this.tokenID = tokenPK;
    }
    public Long getFileID()
    {
        return fileID;
    }
    public void setFileID(Long filePK)
    {
        this.fileID = filePK;
    }
    public Long getTransID()
    {
        return transID;
    }
    public void setTransID(Long transID)
    {
        this.transID = transID;
    }
    public Long getUniqueTokenID()
    {
        return uniqueToken.getUniqueTokenID();
    }
    public void setUniqueTokenID(Long uniqueTokenID)
    {
        uniqueToken.setUniqueTokenID(uniqueTokenID);
    }

    public String getImage()
    {
        return uniqueToken.getImage();
    }

    public String getKind()
    {
        return uniqueToken.getKind();
    }

    public void setImage(String image)
    {
        uniqueToken.setImage(image);
    }

    public void setKind(String kind)
    {
        uniqueToken.setKind(kind);
    }

    /**
	 * @param other the other SCToken to compare against
	 * @return the normalized Levenstein edit distance
	 */
	public double getNormalizedLevenshteinEditDistance(SCToken other)
	{
		double nEditDist;
		String thisTokenImage, otherTokenImage;
		
		thisTokenImage = this.getImage();
		otherTokenImage = other.getImage();
		
		nEditDist = org.apache.commons.lang.StringUtils.getLevenshteinDistance(thisTokenImage, otherTokenImage);
		nEditDist /= ( java.lang.Math.max(thisTokenImage.length(), otherTokenImage.length()));
		return nEditDist;
	}
	
	public static final String ARITHMETIC="arithmetic";
	public static final String LOGICAL="logical";
	public static final String BIT="bit";
	public static final String PUNCTUATION="punctuation";
	public static final String ASSIGNMENT="assignment";
	public static final String KEYWORD="keyword";
	public static final String TYPE="type";
	
	public static String convertPMDTokenKindToDBEnum(int kind)
    {
        String s=JavaParserConstants.tokenImage[kind];
        s=s.replace("\"", "").toLowerCase();
        if (kind <= 74)
            s=s.replaceAll("<|>","");
        if (arithmetic.contains(s))
            return ARITHMETIC;
        if (logical.contains(s))
            return LOGICAL;
        if (bit.contains(s))
            return BIT;
        if (punctuation.contains(s))
            return PUNCTUATION;
        if (assignment.contains(s))
            return ASSIGNMENT;
        if (keyword.contains(s))
            return KEYWORD;
        if (type.contains(s))
            return TYPE;
        return s;
    }
    
    private static final Set<String> arithmetic=new HashSet<String>();
    private static final Set<String> logical=new HashSet<String>();
    private static final Set<String> bit=new HashSet<String>();
    private static final Set<String> punctuation=new HashSet<String>();
    private static final Set<String> assignment=new HashSet<String>();
    private static final Set<String> keyword=new HashSet<String>();
    private static final Set<String> type=new HashSet<String>();
    

    static {
        for (String s : new String[] {"+", "-", "*", "/", "%", "++", "--"}) {
            arithmetic.add(s);
        }
        for (String s : new String[] {"&&", "||", "!", ">", "<", ">=", "<=", "==", "!=" }) {
            logical.add(s);
        }
        for (String s : new String[] {"&", "|", "^", "~", ">>", "<<", ">>>"}) {
            bit.add(s);
        }
        for (String s : new String[] {"(", ")", "[", "]", ";", ".", "@", "?", ":", ","}) {
            punctuation.add(s);
        }
        for (String s : new String[] {"=", "+=", "-=", "/=", "*=", "%=", 
                "&=", "|=", ">>=", "<<=", ">>>=", "^="}) {
            assignment.add(s);
        }
        for (String s : new String[] {"boolean", "byte", "char", "double", "float",
                "int", "long", "short", }) {
            type.add(s);
        }
        for (String s : new String[] {"abstract", "break", "case", "catch", "class", 
                "const", "continue", "default", "do", "else", "extends", "false", 
                "final", "finally", "for", "goto", "if", "implements", "import",
                "instanceof", "interface", "native", "new", "null", "package",
                "private", "protected", "public", "return", "static", "super",
                "switch", "synchronized", "this", "throw", "throws", "transient", 
                "true", "try", "void", "volatile", "while", "strictfp"}) {
            keyword.add(s);
        }
    }


    void setUniqueToken(UniqueToken u)
    {
        uniqueToken=u;
    }

    

}
